package rad.framework.mda.jpagen.actions;

import java.io.PrintWriter;
import java.io.StringWriter;

import rad.framework.mda.generator.Console;
import rad.framework.mda.util.ModelUtil;

import org.eclipse.emf.common.util.EList;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.uml2.uml.Class;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.Enumeration;
import org.eclipse.uml2.uml.NamedElement;
import org.eclipse.uml2.uml.Property;
import org.eclipse.uml2.uml.Stereotype;

/**
 * @author boudyacho
 *
 */
public class AddForeignKeyActionExtension extends
		BaseUtiltiyActionExtension {

	protected static final String M2O = "javax.persistence.ManyToOne";

	protected static final String O2O = "javax.persistence.OneToOne";

	protected static final String M2M = "javax.persistence.ManyToMany";

	protected static final String FOREIGN_KEY = "org.hibernate.annotations.ForeignKey";

	protected static final String NAME = "name";
	
	protected static final String INVERSE_NAME = "inverseName";

	public void fillContextMenu(IMenuManager aMenu) {
		getSubMenu(aMenu).add(new AddForeignKeyAction());
	}

	protected void execute(Class clazz) {
		EList<NamedElement> list = clazz.getMembers();
		for (NamedElement namedElement : list) {
			if (namedElement instanceof Property) {
				execute((Property) namedElement);
			}
		}
	}

	protected void execute(Property property) {
		// TODO define a way to plugin these rules in a profile
		// plugin.xml file
		if (ModelUtil.isStereotypeApplied(property, M2O) || ModelUtil.isStereotypeApplied(property, O2O)) {
			addM2OForeignKey(property);
		}
		if (ModelUtil.isStereotypeApplied(property, M2M)) {
			addM2MForeignKey(property);
		}
	}

	protected void addM2OForeignKey(Property property) {
		Stereotype stereotype = (Stereotype) ModelUtil.getProfileElement(
				property, FOREIGN_KEY);
		if (stereotype != null) {
			if (ModelUtil.isStereotypeApplied(property, FOREIGN_KEY)) {
				property.unapplyStereotype(stereotype);
			}
			
			StringBuffer fk = new StringBuffer();
			fk.append("FK_" + NameUtil.getAbbreviation((NamedElement)property.getOwner()));
			fk.append("_TO_");
			fk.append(NameUtil.getAbbreviation(property));			
			property.applyStereotype(stereotype);
			fk = new StringBuffer(NameUtil.getAbbreviation(fk.toString()));
			property.setValue(stereotype, NAME, fk.toString());
			checkLength(property, fk.toString(), 30);
			Console.getStream().println(
					"Added Foreign Key " + fk.toString() + " for " + property.getQualifiedName());
		}
	}

	protected void addM2MForeignKey(Property property) {
		Stereotype stereotype = (Stereotype) ModelUtil.getProfileElement(
				property, FOREIGN_KEY);
		if (stereotype != null) {
			if (ModelUtil.isStereotypeApplied(property, FOREIGN_KEY)) {
				property.unapplyStereotype(stereotype);
			}
			
			StringBuffer fk = new StringBuffer();
			fk.append("FK_" + NameUtil.getAbbreviation((NamedElement)property.getOwner()));
			fk.append("_TO_");
			fk.append(NameUtil.getAbbreviation(property));	
			
			StringBuffer inverseFk = new StringBuffer();
			inverseFk.append("FK_" + NameUtil.getAbbreviation(property));
			inverseFk.append("_TO_");
			inverseFk.append(NameUtil.getAbbreviation((NamedElement)property.getOwner()));	
			property.applyStereotype(stereotype);
			property.setValue(stereotype, NAME, fk.toString());
			property.setValue(stereotype, INVERSE_NAME, inverseFk.toString());
			fk = new StringBuffer(NameUtil.getAbbreviation(fk.toString()));
			inverseFk = new StringBuffer(NameUtil.getAbbreviation(inverseFk.toString()));
			checkLength(property, fk.toString(), 30);
			checkLength(property, inverseFk.toString(), 30);
			Console.getStream().println(
					"Added Foreign Key " + fk.toString() + " for " + property.getQualifiedName());
			Console.getStream().println(
					"Added Foreign Key " + inverseFk.toString() + " for " + property.getQualifiedName());
		}
	}

	private class AddForeignKeyAction extends BaseUtilityAction {
		private static final String LABEL = "Add Foreign Keys";

		public AddForeignKeyAction() {
			super(LABEL);
		}
	}
}
